﻿using System;

using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using RaisingStudio.Data.Providers;
using RaisingStudio.Data;
using RaisingStudio.Data.Entities;
using RaisingStudio.Data.Common;

using RaisingStudio.Linq;
using RaisingStudio.Data.Linq;
using RaisingStudio.Data.Common.Factories;

namespace SmartDeviceProject1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

 #if CF_1_0 || CF_2_0
           ClearTempFolder();
#endif
            this.Assert = new TestAssert(this.WriteLog);
        }

  #if CF_1_0 || CF_2_0
        private string GetAssemblyName(System.Linq.Expressions.Expression expression)
        {
            return System.IO.Path.GetTempFileName();
        }

        private void ClearTempFolder()
        {
            System.Linq.Expressions.LambdaExpression.GetAssemblyName = this.GetAssemblyName;
        }
#endif

        private void button1_Click(object sender, EventArgs e)
        {
            string connectionString = string.Format("Data Source={0}\\AppDatabase1.sdf;Persist Security Info=False;", (System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase)));
            DataContext dc = new DataContext(DatabaseType.SQLCE, connectionString);
            // log to console.
            //dc.Log = System.Console.Out;
            // log to a string.
            //System.IO.StringWriter stringWriter = new System.IO.StringWriter();
            //dc.Log = stringWriter;
            // log to debug.
            dc.Log = new LogMethodWrapper(WriteLog);

            WriteLog(dc.UseDynamicProxy);
            dc.UseDynamicProxy = true;
            
            Issue issue = new Issue();
            issue.Title = "test";
            issue.Status = IssueStatus.New;
            issue.IssueType = IssueType.Issue;
            issue.CreateTime = DateTime.Now;
            dc.Insert<Issue>(issue);

            Issue issue2 = dc.GetData<Issue>(1);
            MessageBox.Show(issue2.Title);

            List<int> issueIDList = dc.ExecuteForList<int>(new CommonCommand("SELECT ISSUE_ID FROM DAC_ISSUE"));
            MessageBox.Show(issueIDList.Count.ToString());

            SystemUser user = new SystemUser();
            user.ChangingPassword = false;
            user.FullName = "full name";
            user.Password = "pwd";
            user.UserID = "test_user";
            user.UserName = "test user name";
            dc.Save<SystemUser>(user);

            MessageBox.Show(dc.QueryForList<SystemUser>(SystemUser._.UserName == "test user name").Count.ToString());

            var q = from s in dc.GetQueryableData<SystemUser>()
                    where s.UserName == user.UserName
                    select s;
            foreach (var s in q)
            {
                MessageBox.Show(s.UserName);
            }

            //DebugWrite(stringWriter);
        }

        public void WriteLog(object value)
        {
            string fileName = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase), "log.txt");
            using (System.IO.StreamWriter streamWriter = System.IO.File.AppendText(fileName))
            {
                streamWriter.WriteLine(value);
            } 
            System.Diagnostics.Debug.WriteLine(value);
        }

        private static void DebugWrite(System.IO.StringWriter stringWriter)
        {
            stringWriter.Flush();
            System.IO.StringReader stringReader = new System.IO.StringReader(stringWriter.ToString());
            while (true)
            {
                string aLine = stringReader.ReadLine();
                if (aLine != null)
                {
                    System.Diagnostics.Debug.WriteLine(aLine);
                }
                else
                {
                    break;
                }
            }
        }

        private DataContext dc;
        private List<int> issueList;

        public const string ISSUETITLE_FORTEST = "Issue Title for UnitTest";

        private void CreateDataContext()
        {
            //this.dc = new DataContext();
            //this.dc.Log = System.Console.Out;
            string connectionString = string.Format("Data Source={0}\\AppDatabase1.sdf;Persist Security Info=False;", (System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase)));
            this.dc = new DataContext(DatabaseType.SQLCE, connectionString);
            this.dc.Log = new LogMethodWrapper(WriteLog);
        }

        private void InsertDummyData()
        {
            this.issueList = new List<int>();
            try
            {
                this.dc.BeginTransaction();
                try
                {
                    Issue issue = new Issue();
                    issue.CreateTime = System.DateTime.Now;
                    issue.Description = "Issue for UnitTest.";
                    issue.IssueType = IssueType.Issue;
                    issue.Locked = false;
                    issue.Owner = "sa";
                    issue.Progress = 10;
                    issue.Status = IssueStatus.New;
                    issue.Title = ISSUETITLE_FORTEST;
                    this.dc.Insert<Issue>(issue);
                    this.issueList.Add(Convert.ToInt32(this.dc.GetMax<Issue>(Issue._.IssueID)));

                    Issue issue2 = new Issue();
                    issue2.CreateTime = System.DateTime.Now;
                    issue2.Description = "Issue2 for UnitTest.";
                    issue2.Progress = 20.34M;
                    issue2.Status = IssueStatus.Fixed;
                    issue2.Title = ISSUETITLE_FORTEST;
                    this.dc.Insert<Issue>(issue2);
                    this.issueList.Add(Convert.ToInt32(this.dc.GetMax<Issue>(Issue._.IssueID)));

                    this.dc.CommitTransaction();
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex);
                    this.dc.RollbackTransaction();
                    throw;
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex);
                throw;
            }
        }

        private void ClearDummyData()
        {
            if (this.dc != null)
            {
                try
                {
                    this.dc.BeginTransaction();
                    try
                    {
                        foreach (int issueID in this.issueList)
                        {
                            this.dc.Delete<Issue>(issueID);
                        }

                        this.dc.CommitTransaction();
                    }
                    catch (Exception ex)
                    {
                        System.Diagnostics.Debug.WriteLine(ex);
                        this.dc.RollbackTransaction();
                        throw;
                    }
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex);
                    throw;
                }
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            CreateDataContext();
            InsertDummyData();

            Test1();
            Test2();
            Test3();
            Test4();
            Test5();
            Test6();
            Test7();
            Test8();
            Test9();
            Test10();
            Test14();

            TestMethod1();
            TestMethod2();
            TestMethod3();

            ClearDummyData();
        }

        public TestAssert Assert { get; set; }


        [Test]
        public void Test1()
        {
            Assert.IsNotNull(this.dc);
            Assert.IsNotNull(this.dc.Connection);
            Assert.IsNotNull(this.dc.Database);
            Assert.IsNotNull(this.dc.Provider);
            Assert.IsNotNull(this.dc.LogManager);

            Assert.IsTrue(this.dc.GetCount<Issue>() > 0);
        }

        [Test]
        public void Test2()
        {
            QueryableData<Issue> issues = new QueryableData<Issue>(dc);
            var il = from s in issues
                     where s.IssueID > 0 && s.Title != ISSUETITLE_FORTEST || (bool)s.Locked == true
                     select s;
            foreach (var issue in il)
            {
                Assert.IsTrue(issue.IssueID > 0);
            }

            var il2 = from s in issues
                      where s.IssueID > 0
                      orderby s.IssueID descending
                      select s;
            foreach (var issue in il2)
            {
                Assert.IsTrue(issue.IssueID > 0);
            }

            var a = (from s in (this.dc.GetQueryableData<Issue>()) select s);
            Assert.IsNotNull(a);
            // TODO:
            Assert.AreEqual(this.dc.GetCount<Issue>(), this.dc.GetCount<Issue>(a));
            Assert.AreEqual(this.dc.GetCount<Issue>(), a.Count());

            var b = (from s in (new RaisingStudio.Data.Expressions.QueryExpression<Issue>()) select s);
            System.Data.DataTable dt1 = this.dc.QueryForDataTable<Issue>(b);
            Assert.IsNotNull(dt1);
            Assert.AreEqual(this.dc.GetCount<Issue>(), dt1.Rows.Count);

            var c = (from s in (this.dc.GetExpressionData<_Issue, Issue>(Issue._)) select s);
            System.Data.DataTable dt2 = c.QueryForDataTable();
            Assert.IsNotNull(dt2);
            Assert.AreEqual(this.dc.GetCount<Issue>(), dt2.Rows.Count);

            var dataTable = this.dc.QueryForDataTable<Issue>(Issue._, Issue._);

            var issueList = (this.dc.GetExpressionData<_Issue, Issue>((from s in Issue._ select s))).QueryForList<Issue>();
            Assert.IsNotNull(issueList);
            Assert.AreEqual(dataTable.Rows.Count, issueList.Count);
            Assert.IsNotNull(issueList[0]);
            Assert.IsNotNull(issueList[0].Title);
        }

        [Test]
        public void Test3()
        {
            Test3_3(Test3_2(Test3_1()));
        }

        [Test]
        public int Test3_1()
        {
            int maxID = this.dc.GetMax<Issue, int>(from s in Issue._ select s.IssueID);
            var q = (IQueryableData)(from s in this.dc.GetQueryableData<Issue>() select s.IssueID);
            Assert.AreEqual(maxID, q.GetMax<Issue, int>());
            return maxID;
        }

        [Test]
        public decimal Test3_2(int maxID)
        {
            decimal originalProgress = this.dc.QueryForSingle<Issue>(from s in Issue._ where s.IssueID == maxID select s.Progress).Progress.Value;
            int result = this.dc.UpdateByQuery<Issue>(new Issue { Progress = originalProgress + 1 }, (from s in Issue._ where s.IssueID == maxID select s.Progress));
            Assert.AreEqual(1, result);
            return originalProgress;
        }

        [Test]
        public void Test3_3(decimal originalProgress)
        {
#if SQLCE
            int issueID = Convert.ToInt32(this.dc.GetMax<Issue>(Issue._.IssueID));
            decimal currrentProgress = this.dc.QueryForSingle<Issue>(from s in Issue._ where s.IssueID == issueID select s.Progress).Progress.Value;
            Assert.AreEqual(originalProgress + 1, currrentProgress);
#else
            decimal currrentProgress = this.dc.QueryForSingle<Issue>(from s in Issue._ where s.IssueID == s.IssueID.Max select s.Progress).Progress.Value;
            Assert.AreEqual(originalProgress + 1, currrentProgress);
#endif
        }

        [Test]
        public void Test4()
        {
            var q = from s in this.dc.GetExpressionData<_Issue, Issue>(Issue._)
                    where s.Title == ISSUETITLE_FORTEST
                    select s;
            int count = 0;
            foreach (Issue issue in q)
            {
                Assert.AreEqual(ISSUETITLE_FORTEST, issue.Title);
                count++;
            }
            Assert.GreaterOrEqual(count, 1);

            count = 0;
            foreach (var issue in q.Query(0, 1))
            {
                Assert.AreEqual(ISSUETITLE_FORTEST, issue.Title);
                count++;
            }
            Assert.AreEqual(1, count);
        }

        [Test]
        public void Test5()
        {
            // TODO:            
            var i = this.dc.GetQueryableData<Issue>();
            // TODO: partial column in Queryable LINQ.           
#if CF_1_0 || CF_2_0
            foreach (var item in from s in ((from s in i where s.Title == ISSUETITLE_FORTEST select s) as IEnumerable<Issue>) select new { s.IssueID, s.Title })
            {
                Assert.AreEqual(ISSUETITLE_FORTEST, item.Title);
            }
#else
            foreach (var item in from s in i where s.Title == ISSUETITLE_FORTEST select new { s.IssueID, s.Title })
            {
                Assert.AreEqual(ISSUETITLE_FORTEST, item.Title);
            }
#endif

#if CF_1_0 || CF_2_0
#else
            foreach (var item in this.dc.Query<Issue>(from s in i where s.Title == ISSUETITLE_FORTEST select new { s.IssueID, s.Title }))
            {
                Assert.AreEqual(ISSUETITLE_FORTEST, item.Title);
            }
#endif
            var q = this.dc.GetExpressionData<_Issue, Issue>(Issue._);
            int count = 0;
#if CF_1_0 || CF_2_0
            foreach (var item in from s in (from s in q where s.Title == ISSUETITLE_FORTEST select s) as IEnumerable<Issue> select new { s.IssueID, s.Title })
            {
                Assert.AreEqual(ISSUETITLE_FORTEST, item.Title);
                count++;
            }
            Assert.GreaterOrEqual(count, 1);
#else
            foreach (var item in from s in q where s.Title == ISSUETITLE_FORTEST select new { s.IssueID, s.Title })
            {
                Assert.AreEqual(ISSUETITLE_FORTEST, item.Title);
                count++;
            }
            Assert.GreaterOrEqual(count, 1);
#endif

            decimal value = 10;
            count = 0;
            foreach (var item in from s in q where s.Progress >= value select s.Progress)
            {
                Assert.GreaterOrEqual(item.Progress, value);
                count++;
            }
            Assert.GreaterOrEqual(count, 1);
        }

        [Test]
        public void Test6()
        {
            var q = new ExpressionData<_Issue, Issue>(this.dc, Issue._);
            Assert.AreEqual(this.dc.GetMax<Issue>(Issue._.Progress), (from s in q select s.Progress).GetMax<Issue, decimal>());

            var q2 = (from s in (new ExpressionData<_Issue, Issue>(this.dc, Issue._)) select s.Progress);
            Assert.AreEqual(this.dc.GetMax<Issue>(Issue._.Progress), q2.GetMax());
        }

        [Test]
        public void Test7()
        {
            // TODO: GetData, Delete, Exists ...
            Assert.IsTrue(this.dc.Exists<Issue>(this.issueList[0]));
            Assert.IsTrue(this.dc.ExistsByQuery<Issue>(from s in Issue._ where s.Title == ISSUETITLE_FORTEST select s));
            // TODO:
            Assert.IsTrue(this.dc.ExistsByQuery<Issue>(s => s.Title == ISSUETITLE_FORTEST));
            Assert.IsTrue((from s in new ExpressionData<_Issue, Issue>(this.dc, Issue._) where s.Title == ISSUETITLE_FORTEST select s).Exists());
        }

        [Test]
        public void Test8()
        {
            // TODO: 
            decimal avg = Convert.ToDecimal(this.dc.GetAvg<Issue>(s => s.Progress));
            decimal avg2 = this.dc.GetAvg<Issue, decimal>(from s in Issue._ select s.Progress);
            Assert.AreEqual(this.dc.GetAvg<Issue>(Issue._.Progress), avg);
            Assert.AreEqual(avg, avg2);
        }

        [Test]
        public void Test9()
        {
            int count = this.dc.GetCount<Issue>();
            Assert.GreaterOrEqual(count, 1);

 #if CF_1_0 || CF_2_0
            var value = this.issueList[0];
           count = this.dc.GetCount<Issue>(s => s.IssueID == value);
            Assert.AreEqual(1, count);
#else
           count = this.dc.GetCount<Issue>(s => s.IssueID == this.issueList[0]);
            Assert.AreEqual(1, count);
#endif

 #if CF_1_0 || CF_2_0
            var value2 = this.issueList[0];
            count = this.dc.GetCount<Issue>(from s in Issue._ where s.IssueID == value2 | s.Title == ISSUETITLE_FORTEST select s);
            Assert.GreaterOrEqual(count, 1);
#else
           count = this.dc.GetCount<Issue>(from s in Issue._ where s.IssueID == this.issueList[0] | s.Title == ISSUETITLE_FORTEST select s);
            Assert.GreaterOrEqual(count, 1);
#endif

#if CF_1_0 || CF_2_0
            var q = new ExpressionData<_Issue, Issue>(this.dc, Issue._);
            var value3 = this.issueList[0];
            count = (from s in q where s.IssueID == 3 | s.Title == ISSUETITLE_FORTEST select s).GetCount();
            Assert.GreaterOrEqual(count, 1);
#else
            var q = new ExpressionData<_Issue, Issue>(this.dc, Issue._);
            count = (from s in q where s.IssueID == this.issueList[0] | s.Title == ISSUETITLE_FORTEST select s).GetCount();
            Assert.GreaterOrEqual(count, 1);
#endif
        }

        [Test]
        public void Test10()
        {
            // TODO:
#if CF_1_0 || CF_2_0
            var value = this.issueList[0];
            Issue issue = this.dc.QueryForSingle<Issue>(s => s.IssueID == value);
            //Issue issue = this.dc.GetData<Issue>(this.issueList[0]);
            var i2 = this.dc.QueryForSingle<Issue>(from s in Issue._ where s.IssueID == value select s);
            Assert.AreEqual(issue.IssueID, i2.IssueID);
#else
            Issue issue = this.dc.QueryForSingle<Issue>(s => s.IssueID == this.issueList[0]);
            //Issue issue = this.dc.GetData<Issue>(this.issueList[0]);
            var i2 = this.dc.QueryForSingle<Issue>(from s in Issue._ where s.IssueID == this.issueList[0] select s);
            Assert.AreEqual(issue.IssueID, i2.IssueID);
#endif
        }


        [Test]
        public void Test14()
        {
            var q = this.dc.Query<Issue>(from s in Issue._ orderby s.IssueID select s);
            int count = 0;
            int issueID = 0;
            foreach (var issue in q)
            {
                Assert.Greater(issue.IssueID, issueID);
                issueID = issue.IssueID;
                count++;
            }
            Assert.Greater(count, 0);
            var q2 = (from s in (new ExpressionData<_Issue, Issue>(this.dc, Issue._)) orderby s.IssueID descending select s);
            count = 0;
            foreach (var issue in q2)
            {
                Assert.LessOrEqual(issue.IssueID, issueID);
                issueID = issue.IssueID;
                count++;
            }
            Assert.Greater(count, 0);
        }


        [Test]
        public void TestMethod1()
        {
            QueryableData<Issue> issues = new QueryableData<Issue>(dc);
            var il = from s in issues where s.IssueID > 0 select s;
            foreach (var issue in il)
            {
                Assert.IsTrue(issue.IssueID > 0);
            }

            var il2 = from s in issues where s.IssueID > 0 && s.Title == ISSUETITLE_FORTEST select s;
            foreach (var i in il2)
            {
                Assert.IsTrue(i.IssueID > 0);
                Assert.IsTrue(i.Title == ISSUETITLE_FORTEST);
            }
        }

        [Test]
        public void TestMethod2()
        {
           var a = (from s in (this.dc.GetQueryableData<Issue>()) select s);
            Assert.IsNotNull(a);
            // TODO: function for Queryable LINQ.
            Assert.AreEqual(this.dc.GetCount<Issue>(), a.Count());
            Assert.AreEqual(this.dc.GetCount<Issue>(), this.dc.GetCount<Issue>(a));

            Assert.AreEqual(this.dc.GetCount<Issue>(), this.dc.GetQueryableData<Issue>().Count());

#if CF_1_0 || CF_2_0
            var value = this.issueList[0];
            var b = (from s in (this.dc.GetQueryableData<Issue>()) where s.IssueID == value select s);
            Assert.AreEqual(this.dc.GetCount<Issue>(Issue._.IssueID == value), b.Count());
#else
            var b = (from s in (this.dc.GetQueryableData<Issue>()) where s.IssueID == this.issueList[0] select s);
            Assert.AreEqual(this.dc.GetCount<Issue>(Issue._.IssueID == this.issueList[0]), b.Count());
#endif

            var i = this.dc.GetQueryableData<Issue>();
            // TODO: partial column in Queryable LINQ.                      
 #if CF_1_0 || CF_2_0
           foreach (var item in from s in (from s in i where s.Title == ISSUETITLE_FORTEST select s) as IEnumerable<Issue> select new { s.IssueID, s.Title })
            {
                Assert.AreEqual(ISSUETITLE_FORTEST, item.Title);
            }
#else
           foreach (var item in from s in i where s.Title == ISSUETITLE_FORTEST select new { s.IssueID, s.Title })
            {
                Assert.AreEqual(ISSUETITLE_FORTEST, item.Title);
            }
            foreach (var item in this.dc.Query<Issue>(from s in i where s.Title == ISSUETITLE_FORTEST select new { s.IssueID, s.Title }))
            {
                Assert.AreEqual(ISSUETITLE_FORTEST, item.Title);
            }
#endif
        }

        [Test]
        public void TestMethod3()
        {
            var b = (from s in (this.dc.GetQueryableData<Issue>()) select s.IssueID);
            Assert.IsNotNull(b);
            // TODO: function for Queryable LINQ.
            Assert.AreEqual(this.dc.GetAvg<Issue, double>(b), b.Average());
            Assert.AreEqual(this.dc.GetMax<Issue, int>(b), b.Max());
            Assert.AreEqual(this.dc.GetMin<Issue, int>(b), b.Min());
            Assert.AreEqual(this.dc.GetSum<Issue, int>(b), b.Sum());

            var a = (from s in (this.dc.GetQueryableData<Issue>()) where s.IssueID > 0 select s.IssueID);
            Assert.IsNotNull(a);
            // TODO: function for Queryable LINQ.
            Assert.AreEqual(this.dc.GetAvg<Issue, double>(a), a.Average());
            Assert.AreEqual(this.dc.GetMax<Issue, int>(a), a.Max());
            Assert.AreEqual(this.dc.GetMin<Issue, int>(a), a.Min());
            Assert.AreEqual(this.dc.GetSum<Issue, int>(a), a.Sum());
        }

        private void button3_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void button4_Click(object sender, EventArgs e)
        {
            ObjectAccessorFactory factory = new ObjectAccessorFactory();
            Dictionary<string, System.Type>  propertyTypes;
            IObjectAccessor accessor = factory.CreateObjectAccessor(typeof(Issue), new string[] { "IssueID", "Title", "Description", "Status", "IssueType", "Owner", "Progress", "CreateTime", "Locked" }, out propertyTypes);
            Issue issue = new Issue();
            accessor.SetValue(issue, "IssueID", 1);
            accessor.SetValue(issue, "Title", "issue for Test");
            string value = accessor.GetValue(issue, "Title") as string;
            MessageBox.Show(value);
        }
    }
}